﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.DigitalTwinAlignment.CApSrServer
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Tecnomatix.Engineering;


namespace DnProcessSimulateCommands.DigitalTwinAlignment;

internal class CApSrServer
{
  private readonly SynchronizationContext _mainThreadContext;
  private readonly ConcurrentQueue<string> _receiveQueue;
  private readonly TcpListener _listener;
  public bool beamModel = true;

  public CApSrServer()
  {
    this._mainThreadContext = SynchronizationContext.Current;
    this._receiveQueue = new ConcurrentQueue<string>();
    new System.Timers.Timer(500.0) { AutoReset = true, Enabled = true }.Elapsed += new ElapsedEventHandler(this.OnTimedEvent);
    this._listener = new TcpListener(IPAddress.Loopback, 9057);
    this._listener.Start();
    this.StartAccept();
  }

  public void Stop()
  {
    this.Send("shutdown");
    this._listener.Stop();
  }

  private void StartAccept()
  {
    this._listener.BeginAcceptTcpClient(new AsyncCallback(this.AcceptCallback), (object) null);
  }

  private void OnTimedEvent(object _, ElapsedEventArgs __)
  {
    string result;
    if (this._receiveQueue.Count <= 0 || !this._receiveQueue.TryDequeue(out result))
      return;
    int num = result == "export" ? 1 : 0;
  }

  private void AcceptCallback(IAsyncResult AR)
  {
    try
    {
      string str = "";
      using (TcpClient tcpClient = this._listener.EndAcceptTcpClient(AR))
      {
        using (NetworkStream stream = tcpClient.GetStream())
        {
          using (StreamReader streamReader = new StreamReader((Stream) stream, Encoding.Unicode))
            str = streamReader.ReadToEnd();
        }
      }
      switch (str)
      {
        case "plmxBeam":
          this.Send("plmxPrepare");
          this.ExecuteOnMainThread((Action) (() =>
          {
            string exportPath = $"{Path.GetTempPath()}{Path.GetFileNameWithoutExtension(TxApplication.ActiveDocument.FinalDestination)}_study_internal.plmx";
            CApDataManipulator.ExportModel(exportPath);
            this.Send("plmxReady:" + exportPath);
          }));
          break;
        case "srLive":
          this.Send("psLive");
          if (this.beamModel)
          {
            this.beamModel = false;
            this.Send("plmxPrepare");
            this.ExecuteOnMainThread((Action) (() =>
            {
              string exportPath = Path.GetTempFileName() + "study_internal.plmx";
              CApDataManipulator.ExportModel(exportPath);
              this.Send("plmxReady:" + exportPath);
            }));
            break;
          }
          break;
        default:
          if (str.StartsWith("psLicense"))
          {
            this.Send("psLicense" + CApSrServer.GetLicenseString(str.Substring("psLicense".Length)));
            break;
          }
          if (str.StartsWith("align:"))
          {
            string[] alignData = str.Split(':');
            if (alignData.Length == 9)
            {
              TxTransformation transformation = CApDataManipulator.TxTransformationFromRotationAndTranslation(alignData);
              CApDataManipulator.Align(alignData[1], alignData[2], transformation, (Func<TxTransformation, TxTransformation, TxTransformation>) ((t1, t2) => TxTransformation.op_Multiply(t1, t2)));
              break;
            }
            break;
          }
          if (str.StartsWith("alignAbs:"))
          {
            string[] alignData = str.Split(':');
            if (alignData.Length == 15)
            {
              TxTransformation transformation = CApDataManipulator.TxTransformationFromValues(alignData);
              CApDataManipulator.Align(alignData[1], alignData[2], transformation, (Func<TxTransformation, TxTransformation, TxTransformation>) ((t1, t2) => t2));
              break;
            }
            break;
          }
          this._receiveQueue.Enqueue(str);
          break;
      }
      this.StartAccept();
    }
    catch (Exception ex)
    {
      TxApplication.LogWriter.WriteExceptionLine(ex);
    }
  }

  private static string GetLicenseString(string key)
  {
    string machineName = Environment.MachineName;
    string text = $"{DateTime.Now.ToString("dd/MM/yyyy")}1{machineName}";
    return Convert.ToBase64String(CApSrServer.EncryptText(key, text));
  }

  private static byte[] EncryptText(string key, string text)
  {
    byte[] bytes = new UnicodeEncoding().GetBytes(text);
    using (RSACryptoServiceProvider cryptoServiceProvider = new RSACryptoServiceProvider())
    {
      cryptoServiceProvider.FromXmlString(key);
      return cryptoServiceProvider.Encrypt(bytes, true);
    }
  }

  private Task ExecuteOnMainThread(Action callback)
  {
    TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>();
    this._mainThreadContext?.Send((SendOrPostCallback) (_param1 =>
    {
      try
      {
        callback();
        completionSource.SetResult(true);
      }
      catch (Exception ex)
      {
        completionSource.SetException(ex);
      }
    }), (object) null);
    return (Task) completionSource.Task;
  }

  internal bool Send(string message)
  {
    try
    {
      using (TcpClient tcpClient = new TcpClient())
      {
        tcpClient.Connect(IPAddress.Loopback, 9054);
        using (NetworkStream stream = tcpClient.GetStream())
        {
          byte[] bytes = Encoding.Unicode.GetBytes(message);
          stream.Write(bytes, 0, bytes.Length);
          stream.Flush();
        }
        tcpClient.Close();
      }
    }
    catch (ArgumentNullException ex)
    {
      TxApplication.LogWriter.WriteExceptionLine((Exception) ex);
      return false;
    }
    catch (SocketException ex)
    {
      TxApplication.LogWriter.WriteExceptionLine((Exception) ex);
      return false;
    }
    return true;
  }
}
